# Copyright (c) 2011 Andrea Spadaccini <andrea.spadaccini@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

"""Python bindings for the WordReference JSON API."""

__author__ = "Andrea Spadaccini"
__license__ = "GPL v3 or later"
__email__ = "andrea.spadaccini@gmail.com"
__all__ = ['JsonEntry', 'JsonResult']

import os
import logging
import StringIO

# 0.8 is the API version
API_URL_TEMPLATE = "http://api.wordreference.com/0.8/%s/json/%s/%s"

if 'APPLICATION_ID' in os.environ:
    # The app is deployed in Google App Engine, so we will fetch using the
    # URLFetch API and we use Django's simplejson to parse JSON.
    from django.utils import simplejson as json
    from utils import urlfetch_fetch as fetch
    from models import ApplicationData

    # The API key is taken from the datastore
    API_KEY = ApplicationData.get_api_key().value
else:
    # We are in a local test context. We suppose that we are using python 2.6+
    # (json module) and we use urllib2 to query the WR API.
    import json
    from utils import urllib_fetch as fetch

    # The API key is taken from stdin
    API_KEY = raw_input('Insert WordReference.com API Key: ')

class JsonEntry:
    """This class represents an element of an entry block, containing the
    OriginalTerm entry and other translations.
    """
    def __init__(self, entry):
        """Stores string representations of the children"""
        self.elements = []
        self.note = ""
        for key, value in entry.iteritems():
            if key == 'OriginalTerm':
                self.original = JsonEntry.convert_term_to_string(value)
            elif key == "Note":
                self.note = value
            else:
                self.elements.append(JsonEntry.convert_term_to_string(value))

    def __unicode__(self):
        return "%s -> %s" % (self.original, "; ".join(self.elements))

    def __str__(self):
        return self.__unicode__()

    @staticmethod
    def convert_term_to_string(term):
        buf = StringIO.StringIO()
        # 'term' is for sure present in the entry
        buf.write(term['term'])

        # optional fields
        if 'POS' in term and len(term['POS']) > 0:
            buf.write(", %s." % term['POS'])
        if 'sense' in term and len(term['sense']) > 0:
            buf.write(": %s" % term['sense'])
        if 'usage' in term and len(term['usage']) > 0:
            buf.write(" (%s)" % term['usage'])

        ans = buf.getvalue()
        buf.close()
        return ans

class JsonResult:
    def __init__(self, dictionary, word):
        logging.debug('JsonResult.__init__')
        url = API_URL_TEMPLATE % (API_KEY, dictionary, word)
        result = fetch(url)
        logging.debug('Fetched API output (already utf8)')

        # Lists of results
        self.translations = []
        self.compounds = []

        # The API returns invalid Json, as the keys are always the searched word
        # itself. Let's change all the keys to something unique

        data = json.loads(result)
        logging.debug('Parsed JSON')
        # The loaded JSON will contain three important fields,
        # 'PrincipalTranslations' and 'AdditionalTranslations', that contain
        # the translations, and 'Compounds', that contain compound forms.
        #
        # Each of those three fields contains a list of 'Entry' elements. An
        # Entry element is composed by four fields: "term", "POS", "sense" and
        # "usage".
        #
        # We group those entry elements in two lists: translations and
        # compounds.
        if "END" in data:
            del data["END"]
        if "Lines" in data:
            del data["Lines"]

        for term_key, term_value in data.iteritems():
            if 'PrincipalTranslations' in term_value:
                self.translations.extend([JsonEntry(x) for x in term_value['PrincipalTranslations'].values()])

            if 'AdditionalTranslations' in term_value:
                self.translations.extend([JsonEntry(x) for x in term_value['AdditionalTranslations'].values()])

            if 'Compounds' in term_value:
                self.compounds = [JsonEntry(x) for x in term_value['Compounds'].values()]
            # The JSON contains those two unused fields, lines and END, that
            # probably will be used for pagination.
            logging.debug('End of JsonResult.__init__')
